//
//  Copyright 2012 Alin Dobra and Christopher Jermaine
//
//  Licensed under the Apache License, Version 2.0 (the "License");
//  you may not use this file except in compliance with the License.
//  You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS,
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//  See the License for the specific language governing permissions and
//  limitations under the License.
//
#include "CodeLoader.h"
#include "QueryManager.h"
#include "Timer.h"
#include "WorkFuncs.h"

#include <iostream>
#include <iomanip>

/** This version of the code loader loads the code from the Generated.so library
	* previously generated by the code generator. The path to the library needs to
	* be known.
**/


// constructor for the implementation class
CodeLoaderImp::CodeLoaderImp(const char* _srcDir, EventProcessor& _coordinator):
	srcDir(_srcDir)
#ifdef  DEBUG_EVPROC
	,EventProcessorImp(true, "CodeLoader")
#endif
{
	coordinator.copy(_coordinator);

	RegisterMessageProcessor(LoadNewCodeMessage::type, &LoadNewCode, 1
		/* lowest priority */);
}


// GenerateNewCode handler definition
MESSAGE_HANDLER_DEFINITION_BEGIN(CodeLoaderImp, LoadNewCode, LoadNewCodeMessage)
{
	// get code with the current request from the message
	evProc.Load(msg.dirName, msg.configs);

	// return the output to the sender
	LoadedCodeMessage_Factory(evProc.coordinator, msg.configs);
}
MESSAGE_HANDLER_DEFINITION_END


/** Function to load extra dependencies.
    They are read from file Generated/ExtraLibs

*/
void CodeLoaderImp::LoadDependencies(string dirName){
	string modFname = /*dirName +*/ "./Generated/ExtraLibs";

	// read the libs from file
	ifstream file("./Generated/ExtraLibs", ifstream::in);
	while (file.good()){
		string lib;
		file >> lib;

		//if not already loaded
		if (libMap.find(lib) == libMap.end()){
			cout << "Loading " << lib << endl;
			void* module = dlopen(lib.c_str(), RTLD_LAZY | RTLD_GLOBAL);
			libMap[lib]=module;

			if (module == NULL){
				WARNING("Unable to load generated code from file %s!\nThe error is %s.\n",
				      lib.c_str(), dlerror());
			}

		}
	}

	file.close();
}

void CodeLoaderImp::Load(string dirName, WayPointConfigurationList &configMessages){


	void *module = NULL;

	// make the file name for our module
	string modFname = /*dirName +*/ "./Generated/Generated.so";

	LoadDependencies(dirName);

	// open up the module, lazy mode
	module = dlopen(modFname.c_str(), RTLD_LAZY);

	if (module == NULL){
		FATAL("Unable to load generated code from file %s!\nThe error is %s.\n",
			modFname.c_str(), dlerror());
	}

	// now, we will add the code for all our waypoints!
	FOREACH_TWL(wpCfg, configMessages){
		// get waypoint name
		WayPointID wpID = wpCfg.get_myID();
		IDInfo inf;
		wpID.getInfo(inf);
		string wpname = inf.getIDAsString();

		// get list of functions
		WorkFuncContainer& myWorkFuncs = wpCfg.get_funcList();
		
		// scan list
		FOREACH_TWL(funWrap, myWorkFuncs){
			WorkFunc& wFunc = funWrap.get_myFunc();

			if (wFunc != NULL) 
			  printf("Using existing function for %s\n", funWrap.TypeName());
			else {
#ifdef DEBUG
			printf("Processing function %s\n", funWrap.TypeName());
#endif			
			// form the name
			string funName;
			funName += funWrap.TypeName();
			funName += "_";
			funName += wpname;
			
			wFunc = (WorkFunc) dlsym(module, funName.c_str());
			FATALIF(wFunc == NULL, "Unable to obtain function %s from module!", funName.c_str());
#ifdef DEBUG
			printf("Loaded function %s\n", funName.c_str());
#endif
			}
		}END_FOREACH;
		
	}END_FOREACH;

	// close to dynamic library should never be called because than the executable
	// code would not be accessible anymore
	//dlclose(module);
}
